namespace Brjnk.Maps.Downloader
{
    using System;
    using System.ComponentModel;

    /// <summary>
    /// </summary>
    public class DownloadTask : System.ComponentModel.INotifyPropertyChanged
    {
        private byte[] data;

        private Exception exception;

        private bool isCompleted;

        private DownloadTaskPriority priority;

        private long receivedBytes;

        private DownloadTaskState state;

        private object tag;

        private long totalBytes;

        private Uri uri;

        public DownloadTask(Uri url, DownloadTaskPriority priority, object tag, out DownloadTaskUpdater updater)
        {
            this.Uri = url;
            this.Priority = priority;
            this.Tag = tag;
            updater = new DownloadTaskUpdater(
                new Action<DownloadTaskState>(val => this.State = val),
                new Action<DownloadTaskPriority>((val) => this.Priority = val),
               new Action<long>((val) => this.TotalBytes = val),
               new Action<long>((val) => this.ReceivedBytes = val),
               new Action<byte[]>((val) => this.Data = val),
               new Action<Exception>((val) => this.Exception = val),
               new Action(() => this.IsCompleted = true)
            );
        }

        public DownloadTask(Uri url, DownloadTaskPriority priority, out DownloadTaskUpdater updater)
            : this(url, priority, null, out updater) { }

        public event EventHandler Completed;

        // -----------INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        public void RequestCancel()
        {
            cancelRequested = true;
            OnPropertyChanged("CancelRequested");
        }

        private bool cancelRequested;

        public bool CancelRequested { get { return cancelRequested; } }

        public byte[] Data
        {
            get { return data; }
            protected set { data = value; OnPropertyChanged("Data"); }
        }

        public Exception Exception
        {
            get { return exception; }
            protected set { exception = value; OnPropertyChanged("Exception"); }
        }

        public bool IsCompleted
        {
            get { return isCompleted; }
            protected set
            {
                isCompleted = value; OnPropertyChanged("IsCompleted");
                if (isCompleted) OnCompleted();
            }
        }

        public DownloadTaskPriority Priority
        {
            get { return priority; }
            protected set { priority = value; OnPropertyChanged("Priority"); }
        }

        public long ReceivedBytes
        {
            get { return receivedBytes; }
            protected set { receivedBytes = value; OnPropertyChanged("ReceivedBytes"); }
        }

        public DownloadTaskState State
        {
            get { return state; }
            protected set
            {
                state = value;
                OnPropertyChanged("State");
            }
        }

        public object Tag
        {
            get { return tag; }
            set { tag = value; OnPropertyChanged("Tag"); }
        }

        public long TotalBytes
        {
            get { return totalBytes; }
            protected set { totalBytes = value; OnPropertyChanged("TotalBytes"); }
        }

        public Uri Uri
        {
            get { return uri; }
            protected set { uri = value; OnPropertyChanged("Uri"); }
        }

        protected void OnCompleted()
        {
            if (Completed != null) Completed(this, EventArgs.Empty);
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public enum DownloadTaskState
    {
        None,
        Initializing,
        DownloadInProgress,
        Failed,
        FileIsTooShort,
        Success,
        Cancelled
    }
}